<template>
	<div class="cl-upload__wrap">
		<div
			class="cl-upload"
			:class="[
				`cl-upload--${listType}`,
				{
					'is-multiple': multiple,
					'is-drag': drag
				}
			]"
		>
			<!-- <el-input class="cl-upload__hidden" type="hidden" v-model="value" /> -->
			<input type="hidden" v-model="value" />
			<el-upload
				:action="action"
				:accept="_accept"
				:multiple="multiple"
				:limit="limit"
				:data="data"
				:name="_name"
				:drag="drag"
				:class="{ hide : hideUpload }"
				:list-type="listType"
				:file-list="fileList"
				:show-file-list="_showFileList"
				:auto-upload="autoUpload"
				:disabled="disabled || loading"
				:headers="{
					Authorization: token,
					token,
					...headers
				}"
				:http-request="action ? (isBase64 ? httpRequestCustom : undefined) : httpRequest"
				:on-remove="_onRemove"
				:on-preview="_onPreview"
				:on-progress="onProgress"
				:on-change="onChange"
				:on-exceed="_onExceed"
				:on-success="_onSuccess"
				:on-error="_onError"
				:before-upload="_beforeUpload"
				:before-remove="beforeRemove"
				:style="_style"
				v-loading="_loading"
			>
			  <!--<template slot="default" v-if="listType == 'picture-card'">
						<i :class="['cl-upload__icon', _icon]" />
						<span class="cl-upload__text" v-if="_text">{{ _text }}</span>
				</template>
				<div slot="file" slot-scope="{file}" v-if="listType == 'picture-card'">
				    <img v-if="getFileType(_urls[0].url)==='video'" :src="`${_urls[0].url}?x-oss-process=video/snapshot,t_0,f_jpg`" 
									style="width: 150px;height: 150px;"/>
				    <img v-else :src="_urls[0].url" style="width: 150px;height: 150px;"/>
						<span class="el-upload-list__item-actions">
								<span class="el-upload-list__item-preview" @click.stop.prevent="_onPreview(_urls[0])">
										<i class="el-icon-zoom-in"></i>
								</span>
								<span class="el-upload-list__item-delete" 	@click.stop.prevent="_onRemove(_urls[0])">
										<i class="el-icon-delete"></i>
								</span>
						</span>
				</div>
				<el-button
						v-if="listType == 'text'"
						size="mini"
						type="primary"
						:loading="loading"
					>
						点击上传
				</el-button>-->
				<template >
				
					<template v-if="listType == 'picture-card'">
						<i :class="['cl-upload__icon', _icon]" />
						<span class="cl-upload__text" v-if="_text">{{ _text }}</span>
					</template>
					<el-button
						v-else-if="listType == 'text'"
						size="mini"
						type="primary"
						:loading="loading"
					>
						点击上传
					</el-button>
          
					<template v-else>
						<div class="cl-upload__cover" v-if="_urls[0]">
							<img v-if="_urls[0].type == 'image' || isBase64" :src="_urls[0].url" />
							<span v-else>{{ _urls[0].name }}</span>
							<span
								class="cl-upload__cover--action"
								:style="_style"
								v-if="showPreview || showRemove"
							>
								<i
									class="el-icon-zoom-in"
									v-if="showPreview"
									@click.stop.prevent="_onPreview(_urls[0])"
								/>
								<i
									class="el-icon-delete"
									v-if="showRemove"
									@click.stop.prevent="_onRemove(_urls[0])"
								/>
							</span>
						</div>
						<template v-if="!_urls.length">
							<slot name="btn" v-if="$slots.btn"> </slot>
							<template v-else>
								<i :class="['cl-upload__icon', _icon]" />
								<span class="cl-upload__text" v-if="_text">{{ _text }}</span>
							</template>
						</template>
					</template>
				</template>
			</el-upload>
		</div>

		<cl-dialog
			title="图片/视频 预览"
			:visible.sync="preview.visible"
			:props="{
				width: previewWidth,
				appendToBody: true
			}"
		> 
		  <video v-if="getFileType(preview.url) ==='video'" width="100%" 
			    :src="preview.url" controls="controls" ></video>
			<img v-else width="100%" :src="preview.url" alt="" />
		</cl-dialog>
	</div>
</template>

<script>
import { mapGetters } from "vuex";
import path from "path";
import { cloneDeep, last, isArray, isNumber, isEmpty } from "cl-admin/utils";
import { uuid } from "@/utils";
import dayjs from "dayjs";
export default {
	name: "cl-upload",

	props: {
		value: [Array, String],
		// 尺寸
		size: [Array, String, Number],
		// 显示图标
		icon: String,
		// 显示文案
		text: String,
		// 是否以 uuid 重命名
		rename: {
			type: Boolean,
			default: true
		},
		// 最大允许上传文件大小(MB)
		limitSize: {
			type: Number,
			default: 3
		},
		// 预览图片的宽度
		previewWidth: {
			type: String,
			default: "500px"
		},
		// 上传的地址
		action: {
			type: String,
			default: ""
		},
		// 设置上传的请求头部
		headers: Object,
		// 是否多选
		multiple: Boolean,
		// 上传时附带的额外参数
		data: Object,
		// 上传的文件字段名
		name: String,
		// 支持发送 cookie 凭证信息
		withCredentials: Boolean,
		// 是否显示已上传文件列表
		showFileList: {
			type: Boolean,
			default: undefined
		},
		// 是否拖拽
		drag: Boolean,
		// 上传的文件类型
		accept: String,
		// 文件列表的类型
		listType: {
			type: String,
			default: "default"
		},
		// 是否自带上传
		autoUpload: {
			type: Boolean,
			default: true
		},
		// 是否是base64图片
		isBase64: {
			type: Boolean,
			default: false
		},
		showPreview: {
			type: Boolean,
			default: true
		},
		showRemove: {
			type: Boolean,
			default: true
		},
		// 是否禁用
		disabled: Boolean,
		// 最大允许上传个数
		limit: Number,
		// 文件列表移除文件时的钩子
		onRemove: Function,
		// 点击文件列表中已上传的文件时的钩子
		onPreview: Function,
		// 文件上传成功时的钩子
		onSuccess: Function,
		// 文件上传失败时的钩子
		onError: Function,
		// 文件上传时的钩子
		onProgress: Function,
		// 文件状态改变时的钩子
		onChange: Function,
		// 文件超出个数限制时的钩子
		onExceed: Function,
		// 上传文件之前的钩子
		beforeUpload: Function,
		// 删除文件之前的钩子
		beforeRemove: Function
	},

	data() {
		return {
			fileList: [],
			urls: [],
			loading: false,
			preview: {
				visible: false,
				url: null
			}
		};
	},

	computed: {
		...mapGetters(["token", "modules"]),

		conf() {
			return this.modules.upload.options;
		},

		_size() {
			return this.size || this.conf.size || "120px";
		},

		_icon() {
			return this.icon || this.conf.icon || "el-icon-upload";
		},

		_text() {
			return this.text || this.conf.text || "选择文件";
		},

		_accept() {
			let d = this.accept || this.conf.accept;

			switch (this.listType) {
				case "picture-card":
					return d || "image/*";
				default:
					return d;
			}
		},

		_name() {
			return this.name || this.conf.name || "file";
		},

		_limitSize() {
			return this.limitSize || this.conf.limitSize || 2;
		},

		_showFileList() {
			let f = null;

			switch (this.listType) {
				case "picture-card":
				case "text":
					f = true;
					break;
				default:
					f = false;
					break;
			}

			return this.showFileList === undefined ? f : this.showFileList;
		},

		_loading() {
			return this.listType == "default" || this.listType == "picture-card" ? this.loading : false;
		},

		_urls() {
			const format = {
				image: ["bmp", "jpg", "jpeg", "png", "tif", "gif", "svg","mp4"]
			};
			console.log('111111111111')
			return this.urls
				.filter(e => Boolean(e.url))
				.map(e => {
					let arr = e.url.split(".");
					let suf = last(arr);
					return {
						...e,
						type: format.image.includes(suf.toLocaleLowerCase()) ? "image" : null
					};
				});
		},
    
		_style() {
			let arr = [];

			if (isArray(this._size)) {
				arr = this._size;
			} else {
				arr = [this._size, this._size];
			}

			const [height, width] = arr.map(e => (isNumber(e) ? `${e}px` : e));

			if (this.listType == "default" && !this.drag) {
				return {
					height,
					width
				};
			} else {
				return {};
			}
		},
		hideUpload() {
			return this.urls.length >= this.limitSize;
		}
	},

	watch: {
		value: {
			immediate: true,
			handler: "parseValue"
		}
	},
	created() {
		console.log("upload", this.$slots);
	},
	methods: {
		//判断文件后缀名
		getFileType(fileName){
			  console.log(fileName)
			 	let suffix = '';
			// 获取类型结果
				let result = '';
				try {
					const flieArr = fileName.split('.');
					suffix = flieArr[flieArr.length - 1];
				} catch (err) {
					suffix = '';
				}
				console.log(suffix)
			// 匹配 视频
				const videolist = ['mp4', 'm2v', 'mkv', 'rmvb', 'wmv', 'avi', 'flv', 'mov', 'm4v'];
				result = videolist.find(item => item === suffix);
					if (result) {
						return 'video';
					}
			// 图片格式
				const imglist = ['png', 'jpg', 'jpeg', 'bmp', 'gif'];
			// 进行图片匹配
				result = imglist.find(item => item === suffix);
				if (result) {
					return 'image';
				}

		},
		// 解析参数
		parseValue(value) {
			let list = [];

			if (this.multiple) {
				if (value instanceof Array) {
					list = value;
				} else {
					list = (value || "").split(",");
				}
			} else {
				if (value) {
					list = [value];
				}
			}
			// 比较数据，避免重复动画
			if (!this.urls.some(e => list.includes(e.url))) {
				this.fileList = list.filter(Boolean).map(url => {
					return {
						url,
						name: path.basename(url),
						uid: url
					};
				});
				// 设置 URLS
				this.urls = cloneDeep(this.fileList);
			}
		},

		// 更新值
		update() {
			const urls = this.urls
				.filter(e => Boolean(e.url))
				.map(e => e.url)
				.join(",");
			this.$emit("input", urls);
			this.$emit("change", urls);
		},

		// 追加文件
		append(data) {
			if (this.multiple) {
				this.urls.push(data);
			} else {
				this.urls = [data];
			}

			this.update();
		},

		// 关闭上传加载中
		done() {
			this.loading = false;
		},
		_onExceed(files, fileList) {
			if (this.onExceed) {
				this.onExceed(files, fileList);
				return;
			}
			this.$message.warning(`最多上传${this.limit}张图片`);
		},
		// 删除文件
		_onRemove(file) {
			this.urls.splice(
				this.urls.findIndex(e => e.uid === file.uid),
				1
			);
			this.update();

			// 删除文件之前的钩子
			if (this.onRemove) {
				this.onRemove(file, this.urls);
			}
		},

		// 预览图片
		_onPreview(file) {
			this.preview.visible = true;
			this.preview.url = file.url;

			if (!file.url) {
				let item = this.urls.find(e => e.uid == file.uid);

				if (item) {
					this.preview.url = item.url;
				}
			}
		},

		// 上传前
		_beforeUpload(file) {
			this.loading = true;
			file.uri = this.getObjectURL(file);
			if (this._limitSize) {
				if (file.size / 1024 / 1024 >= this._limitSize) {
					this.$message.error(`上传文件大小不能超过 ${this._limitSize}MB!`);
					this.done();
					return false;
				}
			}

			if (this.beforeUpload) {
				return this.beforeUpload(file, {
					done: this.done
				});
			}

			return true;
		},

		getObjectURL(file) {
			let url = null;
			try {
				if (window.createObjectURL != undefined) {
					url = window.createObjectURL(file);
				} else if (window.URL != undefined) {
					url = window.URL.createObjectURL(file);
				} else if (window.webkitURL != undefined) {
					url = window.webkitURL.createObjectURL(file);
				}
			} catch (e) {
				console.log(e);
			}
			return url;
		},
		// 上传成功
		_onSuccess(res, file) {
			// this.loading = false;
			if (!res) return;
			this.append({
				url: this.isBase64 ? file.base64 : res?.data,
				name: file.raw.name,
				uid: file.raw.uid
			});

			// 文件上传成功时的钩子
			if (this.onSuccess) {
				this.onSuccess(res, file.raw, this.urls);
			}
		},
		// 上传失败
		_onError(err, file, fileList) {
			console.log(err);
			this.loading = false;
			// 文件上传失败时的钩子
			if (this.onError) {
				this.onError(err, file, fileList);
			}
			try {
				const error = JSON.parse(err.message);
				this.$message.error(error.msg);
			} catch (e) {
				this.$message.error(err || e.message);
			}
		},
		async httpRequestCustom(req) {
			const mode = await this.uploadMode();
			const upload = file => {
				return new Promise((resolve, reject) => {
					let data = new FormData();

					data.append("pic", file);
					// 上传
					this.$service.common
						.$post(this.action, data, {
							headers: {
								"Content-Type": "multipart/form-data"
							},
							onUploadProgress: e => {
								if (this.onProgress) {
									e.percent = parseInt((e.loaded / e.total) * 100);
									this.onProgress(e, req.file);
								}
							}
						})
						.then(url => {
							if (mode === "local") {
								resolve(url);
							} else {
								resolve(`${res.host}/app/${fileName}`);
							}
						})
						.catch(err => {
							reject(err);
						});
				});
			};

			this.loading = true;

			var reader = new FileReader();
			reader.readAsDataURL(req.file);
			//转base64
			reader.onload = e => {
				// _this.imageUrl = e.target.result //将图片路径赋值给src
				upload(e.target.result)
					.then(url => {
						this._onSuccess({ data: url }, { raw: req.file, base64: e.target.result });
					})
					.catch(err => {
						console.error("upload error", err);
						this.$message.error(err);
						// 	文件上传失败时的钩子
						this._onError(err, req.file);
					})
					.done(() => {
						this.loading = false;
					});
			};
		},
		// 重设上传请求
		async httpRequest(req) {
			const isRename = isEmpty(this.rename) ? this.conf.rename : this.rename;
			const mode = await this.uploadMode();

			// 多种上传请求
			const upload = file => {
				return new Promise((resolve, reject) => {
					const next = res => {
						let data = new FormData();

						for (let i in res) {
							if (i != "host") {
								data.append(i, res[i]);
							}
						}

						let fileName = file.name;

						// 是否以 uuid 重新命名
						if (isRename) {
							fileName = uuid() + "." + last((file.name || "").split("."));
						}

						// data.append("key", `app/${fileName}`);
						data.append("name", fileName);
						data.append("file", file);
						data.append("dirname", "upload/" + dayjs().format("YYYY-MM-DD"));
						// 上传
						this.$service.common
							.$post(res.host, data, {
								url: res.host,
								method: "POST",
								headers: {
									"Content-Type": "multipart/form-data"
								},
								onUploadProgress: e => {
									if (this.onProgress) {
										e.percent = parseInt((e.loaded / e.total) * 100);
										this.onProgress(e, req.file);
									}
								}
							})
							.then(url => {
								if (mode === "local") {
									resolve(url);
								} else {
									resolve(`${res.host}/app/${fileName}`);
								}
							})
							.catch(err => {
								reject(err);
							});
					};

					if (mode == "local") {
						next({
							host: "/index/uposs"
						});
					} else {
						this.$service.common
							.upload()
							.then(res => {
								next(res);
							})
							.catch(reject);
					}
				});
			};

			this.loading = true;

			upload(req.file)
				.then(url => {
					this._onSuccess({ data: url }, { raw: req.file });
				})
				.catch(err => {
					console.error("upload error", err);
					this.$message.error(err);

					// 	文件上传失败时的钩子
					this._onError(err, req.file);
				})
				.done(() => {
					this.loading = false;
				});
		},

		// 上传模式
		uploadMode() {
			return this.$service.common.uploadMode().then(res => res.mode);
		}
	}
};
</script>

<style lang="scss" scoped>
.cl-upload {
	display: flex;
	flex-wrap: wrap;

	&__hidden {
		height: 0;
		width: 0;
	}

	&.is-multiple {
		.cl-upload__wrap {
			margin-right: 10px;
		}
	}

	&--default {
		&:not(.is-drag) {
			::v-deep .el-upload {
				display: flex;
				align-items: center;
				justify-content: center;
				border: 1px dashed #d9d9d9;
				box-sizing: border-box;
				border-radius: 6px;
				cursor: pointer;
				position: relative;
				overflow: hidden;
				height: 100%;

				&:hover {
					border-color: $color-primary;
				}

				.cl-upload__cover {
					// position: relative;
					&--action {
						position: absolute;
						top: 0;
						right: 0;
						width: 100%;
						height: 100%;
						background-color: rgba(0, 0, 0, 0.5);
						opacity: 0;
						transition: opacity 0.3s;
						cursor: default;
						display: flex;
						justify-content: center;
						align-items: center;
						i {
							color: #fff;
							font-size: 20px;
							line-height: 1.8;
							cursor: pointer;
							& + i {
								margin-left: 15px;
							}
						}
						&:hover {
							opacity: 1;
						}
					}
					img {
						display: block;
						height: 100%;
						width: 100%;
					}
				}

				i {
					font-size: 28px;
					color: #8c939d;
				}
			}
		}
	}

	&--picture-card {
		::v-deep .el-upload {
			background-color: #fff;

			.cl-upload__icon {
				position: relative;
				top: 4px;
			}
		}
	}

	&__icon + span {
		margin-left: 5px;
	}

	&__text {
		font-size: 14px;
		color: #999;
	}

	::v-deep {
		.hide .el-upload--picture-card {
    		display: none;
		}
	}
}
</style>
